Skip to content

AI Agent 从概念到实践:一套完整的 RAG + 知识图谱智能客服系统落地全记录

摘要: 本文从 Agent 的基础概念出发,深入拆解其四大核心模块(规划、记忆、工具、行动),结合我们在 VTN 品牌落地的一套完整的知识图谱 RAG 智能客服系统,详细阐述从理论到工程实践的全过程。如果你正在考虑把 AI 能力接入现有业务系统,这篇文章会给你一个可参考的完整路径。

一、什么是 AI Agent?

1.1 从一句话说起

OpenAI 应用研究主管 Lilian Weng 提出了一个被广泛引用的公式:

Agent = LLM + 规划(Planning)+ 记忆(Memory)+ 工具使用(Tool Use)

这个公式的精妙之处在于:它把大模型从一个"回答问题的聊天机器人"提升到了一个"能自主完成任务的智能体"。

打个比方:

  • LLM 是大脑,负责理解和推理
  • 规划 是做计划的能力,把大任务拆成小步骤
  • 记忆 是记住之前发生的事情,不让每次对话都从零开始
  • 工具 是手脚,能搜索网页、调用 API、读写文件

1.2 Agent ≠ ChatGPT 升级版

一个常见的误解是 Agent 就是"更好用的 ChatGPT"。实际上它们有本质区别:

ChatGPT(LLM)AI Agent
核心能力生成文本理解目标 + 自主执行
交互方式一问一答感知 → 思考 → 行动 → 观察 循环
能否调用工具不能(原生)能,这是核心能力
能否处理未知不能,遇到训练外的知识就编造能,通过工具搜索实时信息
类比你问一个人问题,他凭记忆回答你派一个人去完成任务,他会自己想办法

正如一篇分析文章所说:如果 Copilot 是副驾驶,那么 Agent 就是主驾驶。

1.3 人机协同的三个阶段

AI 落地到业务中,人机协同经历了三个阶段:

阶段一:嵌入模式(Embedding) — AI 是工具

用户写 prompt,AI 生成结果。比如用 ChatGPT 写文案、翻译。AI 的角色相当于一个更聪明的搜索引擎。

阶段二:副驾驶模式(Copilot) — AI 是搭档

人类和 AI 共同参与工作流程。比如 GitHub Copilot 帮程序员写代码,人类审核和调整。AI 能提供建议但不做决策。

阶段三:智能体模式(Agent) — AI 是主驾驶

人类设定目标,AI 独立承担大部分工作,人类只做监督和评估。比如 AutoGPT 可以自主完成调研、写报告、写代码。

我们落地的 VTN 智能客服系统,目前处于阶段二到阶段三的过渡:AI 能自主检索知识、生成回答、推荐产品,但在复杂场景下仍需要人类(管理员)通过知识库管理和反馈审核来介入。

二、Agent 四大核心模块深度拆解

2.1 规划(Planning)— 怎么把事做对

规划是 Agent 的"战略制定"能力。它决定了 Agent 如何把一个复杂目标拆解为可执行的子任务。

短期规划 vs 长期规划

短期规划(战术):根据当前环境实时决策下一步做什么。代表项目:

  • AutoGPT:每一步都让 LLM 决定下一步行动
  • ReAct:Thought → Action → Observation 循环

长期规划(战略):在行动开始前就制定完整计划。代表项目:

  • BabyAGI:先生成任务列表,再逐步执行
  • XAgent:外环做长期规划(PlanAgent),内环做短期执行(ToolAgent),形成双循环

我们的实践:

在 VTN 系统中,我们把规划能力用在了查询改写环节。用户问"VC 好处",系统需要自主规划:

  1. 这个问题涉及什么产品/品牌?(实体域识别)
  2. 用户真正想问什么?换几种表述方式(查询扩展)
  3. 用户有没有提到健康问题?(疾病提取)
  4. 用户是想看产品卡还是问问题?(意图识别)

这 4 步并行执行,全部由 GPT-4o 完成。本质上就是一种短期规划——LLM 根据用户输入自主决定"我需要从哪些角度去理解这个问题"。

python
# 核心代码:4路并行查询改写
async def rewrite_query(query_model):
    results = await asyncio.gather(
        detective_query_domain(query_model),      # 1. 实体域识别
        extension_query(query_model),              # 2. 查询扩展
        detective_query_condition(query_model),    # 3. 疾病提取
        query_intent_recognize(query_model),       # 4. 意图识别
    )
    return combine_results(results)

为什么需要意图识别?

这是很多初学者会忽略的问题。想象这个场景:用户之前在看产品,突然说"给我看看一卡通"。

如果不做意图识别,系统会把"一卡通"当成营养问题去知识库检索,然后输出一段关于"什么是产品一卡通"的文字回答——完全不是用户想要的。

意图识别的本质是一个路由器:识别出用户要的是产品卡图片,就短路整个 RAG 流程,直接返回结构化数据。

python
# 意图识别后的短路逻辑
if intents:  # 用户想要产品卡或价格表
    yield format_intent_event(intents, goods_data)
    return  # 不走检索和LLM生成,直接返回

为什么需要查询扩展?

用户输入太短了。"VC 好处"只有 4 个字,直接拿去做向量检索,精度很低。

查询扩展就是让 LLM 从不同角度重新表述同一个问题:

  • 原始:VC 好处
  • 扩展 1:维生素 C 对人体健康有哪些好处?
  • 扩展 2:补充维生素 C 能改善什么健康问题?
  • 扩展 3:维生素 C 的功效与作用是什么?

4 个 query 分别检索,取并集。这就像你去图书馆查资料,只查一个关键词可能漏掉很多相关书,换个说法再查一次,覆盖面就大了。

2.2 记忆(Memory)— 记住发生过什么

Agent 的记忆系统借鉴了人类认知科学的模型,分为三层:

感知记忆(Sensory Memory)

原始输入的向量化表达。在我们的系统中,用户的每一次输入都会被 text-embedding-3-small 转化为 1536 维向量。这就是 Agent 的"感知"。

短期记忆(Short-term Memory)

上下文窗口中最近的对话历史。我们的系统加载最近 4 轮对话(8 条消息),作为 LLM 生成回答时的上下文。

python
# 加载最近4轮对话作为短期记忆
history = get_chat_history_messages(
    chat_id=chat_id,
    user_id=user_id,
    loop_count=4  # 4轮 × 2(user + assistant) = 8条
)

短期记忆的挑战在于上下文窗口有限。GPT-4o 的上下文是 128K,但考虑到成本和延迟,实际可用的只有几 K。我们的做法是截断旧消息——超过 35 个字符的历史消息只保留前 35 字符。

长期记忆(Long-term Memory)

持久化存储在数据库中的历史对话。当对话累积到 3 轮以上时,系统会异步调用 addMemory() 接口,把对话摘要存入长期记忆。

java
// Java网关层的长期记忆逻辑
if (chatItemCount >= lastMemoryChatItemId + 6) {  // 3轮 = 6条消息
    Dc.runAsync(() -> {
        aiMemoryFeignClient.addMemory(chatId, idCode);
    });
}

会话内记忆 vs 会话间记忆

  • 会话内记忆:同一个对话窗口内的多轮对话。用户说"维生素 C 有什么好处",接着问"那每天吃多少",系统需要知道"那"指的是维生素 C。
  • 会话间记忆:跨对话的持久记忆。用户上周问过"BEE+ 蜂蜜怎么吃",这周问"蜂蜜能和维 C 一起吃吗",系统应该记住用户的偏好和历史。

我们的系统通过 chat_historychat_messages 表实现了会话内记忆,通过 AiMemoryFeignClient 实现了会话间记忆的框架。

记忆的妙用

  1. 指代消解:短期记忆让 LLM 理解"它"、"这个产品"指的是什么
  2. 答案缓存:相似问题可以跳过 LLM 推理,直接返回缓存结果
  3. 偏好学习:长期记忆记住用户喜欢什么格式的回答、关心哪些产品
  4. 数据回流:用户的反馈(点赞/踩)可以用于优化知识库和 prompt

2.3 工具使用(Tool Use)— 让 Agent 有手有脚

Agent 的核心突破在于:LLM 不仅能生成文本,还能调用外部工具完成实际操作。

工具使用的演进

  1. WebGPT(2021):让 GPT-3 学会使用浏览器搜索信息
  2. Toolformer(2023):训练 LLM 自主决定何时调用 API
  3. HuggingGPT(2023):让 ChatGPT 调用 HuggingFace 上的专家模型
  4. Function Calling(2023):OpenAI 原生支持,LLM 输出结构化 JSON 调用指定函数

我们的工具使用实践

在 VTN 系统中,Agent 使用了以下"工具":

工具什么时候用怎么用
PGVector 检索用户提问时5 路并行向量搜索,从知识库中找到相关内容
BM25 关键词搜索实体匹配时Jieba 中文分词 → BM25 打分,和向量搜索混合
LLM 查询改写用户提问时4 路并行 GPT-4o 调用,改写和扩展用户问题
Embedding API每次检索前text-embedding-3-small 生成查询向量
商品微服务查询推荐产品时调用内部 API 获取商品详情、价格、图片
FastGPT 知识库健康报告分析时搜索产品功效和禁忌信息
RabbitMQ问答完成后异步发送聊天数据给 Java 网关层持久化

这些工具不是预定义的硬编码流程,而是由 Agent 在不同场景下自主选择调用的。比如:

  • 普通问答 → PGVector + BM25 混合检索 → qwen-max 生成回答
  • 健康报告上传 → GPT-4o OCR → doubao-pro 分析 → FastGPT 匹配产品
  • 企微消息 → 阻塞式调用 vtn-agentic → 拿到完整回答后通过企微 API 发送

2.4 行动(Action)— 把想法变成结果

行动是 Agent 对环境的实际响应。根据任务类型不同,行动可以是:

  • 生成一段文本回答
  • 调用一个 API
  • 执行一段代码
  • 发送一条消息

ReAct 模式

最经典的 Agent 行动模式是 ReAct(Reasoning + Acting):

Thought: 用户问的是维生素C的功效,我需要先检索知识库
Action: PGVector.search("维生素C功效", top_k=20)
Observation: 找到15条相关知识...
Thought: 检索到了足够的信息,现在需要生成回答
Action: LLM.generate(system_prompt, context, user_query)
Observation: 生成了一段关于维生素C功效的回答
Final Answer: 维生素C是一种重要的水溶性维生素...

我们的系统虽然不是标准的 ReAct 循环,但遵循了同样的"思考 → 行动 → 观察"范式,只是把循环次数压缩到了 1 次(规划 → 检索 → 生成),而不是多次迭代。这是工程上在效果和成本之间的权衡

三、知识图谱 + RAG:Agent 的记忆外挂

3.1 为什么 RAG 不够用?

标准 RAG 的流程是:文档 → 分块 → 向量化 → 存入向量库 → 用户查询 → 向量检索 → LLM 生成。

但纯向量检索有几个问题:

  1. 精确匹配差:用户搜"VC"(缩写),向量模型可能不理解
  2. 关系丢失:维生素 C 和免疫系统之间的关系,在向量空间中是模糊的
  3. 领域精度低:全库搜索,可能搜到不相关品牌的产品

3.2 知识图谱怎么补上这些短板?

我们的做法是:在 RAG 的基础上叠加知识图谱,形成 **KG-RAG(Knowledge Graph RAG)**架构。

知识图谱的数据结构

实体(节点):
  - 维生素C(营养素)
  - BEE+ 维生素C片(产品)
  - 免疫系统(身体系统)

关系(边):
  - 维生素C → 免疫系统 [增强免疫, 强度8]
  - 维生素C → 胶原蛋白 [促进合成, 强度7]
  - BEE+ 维生素C片 → 维生素C [含有, 强度10]

知识存储在 PostgreSQL 中,用 PGVector 扩展做向量搜索,关系用专门的 kg_entity_relationships 表存储。

混合检索策略

我们用 5 路并行 PGVector 查询 + BM25 关键词搜索的混合策略:

用户查询 embedding

  ├─ 全局关系搜索(top 20)──── 不带 domain 过滤,覆盖面广
  ├─ 全局问题搜索(top 10)──── 搜 LLM 生成的问题索引
  ├─ 域内关系搜索(top 15)──── 带 WHERE domain IN (...),精度高
  ├─ 域内文本搜索(top 5)───── 搜原始文本片段
  └─ 域内问题搜索(top 5)───── 搜域内 LLM 生成的问题


合并 → 去重 → 过滤(distance > 0.52 的丢弃)→ 最终检索结果

为什么分"域内"和"全局"两组?

  • 域内查询:精度高,但可能漏掉不在已识别域内的知识
  • 全局查询:覆盖面广,但可能混入噪声
  • 两者取并集:用域内保精度,用全局补召回

索引时的查询扩展(镜像策略)

前面讲了搜索时的查询扩展。其实索引时也做了类似的事情——为每个文本块生成"可能被问到的问题":

文本块: "维生素C是水溶性维生素,具有抗氧化作用,可促进胶原蛋白合成"

  │ LLM 生成问题

  "维生素C有什么功效?"
  "维生素C是水溶性还是脂溶性的?"
  "维生素C和胶原蛋白有什么关系?"

这些问题和用户的真实提问方式更接近,向量相似度更高。这就是为什么要有 kg_text_units_index 表。

3.3 实体合并:知识图谱的去重

同一种产品可能在多个文档中被提到,每次描述略有不同。比如:

  • 文档 A:"BEE+ 维生素 C 片,每片含 500mg 维生素 C"
  • 文档 B:"BEE+ 维 C 泡腾片,适合免疫力低下人群"
  • 文档 C:"BEE+ 维 C 产品,可搭配蜂蜜服用"

如果不合并,搜"维生素 C"会搜出 3 条分散的结果。合并后只保留一条最完整的描述,搜索结果更集中、排名更准确。

合并方式是让 LLM 把多条描述综合成一条:

python
# 实体合并的简化逻辑
entities = kg_entities.query(entity_name="维生素C")
merged_description = llm.invoke(
    MERGE_ENTITIES_PROMPT,
    entities=[e.description for e in entities]
)
kg_final_entities.create(
    entity_name="维生素C",
    entity_description=merged_description
)

四、工程实践:一套完整系统的技术架构

4.1 整体架构

┌─────────────┐  ┌──────────────┐
│  前端/App    │  │ 企业微信      │
└──────┬──────┘  └──────┬───────┘
       │                │
       ▼                ▼
┌──────────────────────────────────────────┐
│     agentic-base (Java Spring Boot)      │
│     网关层:认证、路由、会话管理           │
│                                          │
│  ┌────────────┐  ┌─────────────────┐     │
│  │ SSE代理    │  │ 企微消息处理     │     │
│  │ 服务发现   │  │ MQ消费/生产     │     │
│  │ 流量控制   │  │ Redis锁/去重    │     │
│  └────────────┘  └─────────────────┘     │
└────────────────┬─────────────────────────┘
                 │ HTTP (SSE流式 / 阻塞)

┌──────────────────────────────────────────┐
│     vtn-agentic (Python FastAPI)         │
│     AI引擎:RAG + 知识图谱 + LLM推理      │
│                                          │
│  ┌────────────────────────────────┐      │
│  │  RAG 编排器                    │      │
│  │  ┌──────────┐ ┌─────────────┐ │      │
│  │  │ 查询改写  │ │ 知识检索    │ │      │
│  │  │ 4路并行   │ │ 5路并行     │ │      │
│  │  └──────────┘ └─────────────┘ │      │
│  │  ┌──────────┐ ┌─────────────┐ │      │
│  │  │ 答案生成  │ │ 追问建议    │ │      │
│  │  │ qwen-max │ │ qwen-max   │ │      │
│  │  └──────────┘ └─────────────┘ │      │
│  └────────────────────────────────┘      │
└────────────────┬─────────────────────────┘

    ┌────────────┼────────────┬──────────┐
    ▼            ▼            ▼          ▼
 PostgreSQL   RabbitMQ    one-api    FastGPT
 (PGVector)   (异步持久化)  (LLM代理)  (知识库)

4.2 多模型策略

不是所有任务都需要最强的模型。我们的模型选择策略:

任务模型原因
实体域识别GPT-4o需要强推理理解产品关系
查询扩展GPT-4o需要多角度改写
疾病/症状提取GPT-4o医学实体识别要高精度
意图识别GPT-4o分类任务要准确率
Embedding(检索)text-embedding-3-small够用、快、便宜
Embedding(实体匹配)text-embedding-3-large匹配精度要求更高
答案生成qwen-max中文好、成本低
追问建议qwen-max简单任务
健康报告 OCRGPT-4o需要视觉能力
健康报告分析doubao-pro-128k超长上下文
结果重排序gpt-4o-mini简单排序、最便宜

所有模型通过 one-api 代理统一接入,格式统一为 OpenAI 兼容格式。换模型只需在 one-api 后台改配置,代码不动。

4.3 一次问答的完整时序

0ms     前端: POST /api/conversation/completions

8ms     agentic-base: SSO认证 → 服务发现(轮询) → 创建SseEmitter
        │ [新线程] POST → vtn-agentic

18ms    vtn-agentic: 加载聊天历史 (PostgreSQL)

        │ ─── 4路并行LLM改写 (gpt-4o) ───
        │ 实体域识别: 混合搜索(BM25+向量) → LLM提取 ─── 850ms
        │ 查询扩展: LLM生成3个变体 ─── 800ms
        │ 疾病提取: LLM提取 ─── 600ms
        │ 意图识别: LLM分类 ─── 500ms
        │ 总计: ~800ms (并行)

818ms   Embedding: text-embedding-3-small → 768维向量 ~100ms

        │ ─── 5路并行PGVector查询 ─── ~80ms
        │ 合并 + 过滤 ~5ms

903ms   构建prompt: System + History + 知识上下文

        │ ─── qwen-max 流式输出 ───
        │ 首token ~500ms
        │ 完整输出 ~3000ms

3903ms  用户看到完整回答

        │ ─── 后处理 ───
        │ 追问建议 (qwen-max) ~800ms
        │ 写PostgreSQL ~30ms
        │ 发RabbitMQ ~10ms

4743ms  用户看到追问建议,流程结束

        │ (异步) RabbitMQ消费 → agentic-base → MySQL写入 ~50ms

4.4 中间件设计要点

SSE 流式代理

Java 网关层用 SseEmitter 透传 Python 引擎的 SSE 流:

java
SseEmitter emitter = new SseEmitter(5 * 60 * 1000L);
new Thread(() -> {
    restTemplate.execute(url, HttpMethod.POST, request -> {
        request.getHeaders().set("Accept", "text/event-stream");
    }, response -> {
        BufferedReader reader = new BufferedReader(
            new InputStreamReader(response.getBody()));
        String line;
        String eventType = null;
        while ((line = reader.readLine()) != null) {
            if (line.startsWith("event:")) {
                eventType = line.substring(6).trim();
            } else if (line.startsWith("data:")) {
                emitter.send(SseEmitter.event()
                    .name(eventType).data(line.substring(5)));
            }
        }
        emitter.complete();
    });
}).start();

踩坑: Nginx 默认会缓冲 SSE 响应,导致前端收不到实时流。需要配置 proxy_buffering off

自研服务发现

vtn-agentic 是 Python 服务,注册不到 Nacos/Eureka。我们自研了一套轻量级方案:

vtn-agentic 启动 → POST /agentDiscovery/register (注册)
agentic-base 定时 → 异步HTTP探针检查 /health
                    健康 → status=READY
                    不健康 → status=NOT_READY
                    持续不健康30分钟 → 删除实例
选实例 → agent_discovery 表 WHERE status=READY → 轮询

Redis 分布式锁

聊天数据持久化时,vtn-agentic 可能对同一对话并发发多条 MQ 消息。用 Redis 分布式锁防止重复写入:

java
String lockKey = "agentic-base:agent-data-save:"
    + appId + ":" + idCode + ":" + chatId;
DRedisLock lock = new DRedisLock(lockKey);
if (lock.tryLock()) {
    try {
        saveChatData(chatSaveDTO);
    } finally {
        lock.unlock();
    }
}

五、Agent 的挑战与我们的应对

5.1 上下文长度有限

问题: GPT-4o 128K 上下文看起来够用,但考虑成本和延迟,实际可用的很有限。

应对: 旧消息截断(保留前 35 字符)+ 长期记忆摘要 + 检索式历史(只加载最相关的几轮对话,而非最近的全部)。

5.2 LLM 幻觉

问题: 大模型可能编造知识库中没有的内容。

应对: 在 prompt 中严格约束"只根据 <Data> 中的内容回答"。同时存储 message_context 记录每次检索到的知识,方便追溯和优化。

5.3 成本控制

问题: 一次问答涉及 7+ 次 LLM 调用(4 路改写 + 答案生成 + 追问建议 + 可能的重排序),token 消耗大。

应对: 多模型策略——推理任务用 GPT-4o,生成任务用 qwen-max(成本低 5-10 倍),简单排序用 gpt-4o-mini。Embedding 结果缓存到磁盘,避免重复调用。

5.4 中文分词

问题: 向量搜索对缩写("VC")、产品编号("VTN-2024-A001")效果差。

应对: 混合搜索——BM25 关键词搜索做兜底。Jieba 中文分词后用 BM25 打分,和向量搜索结果归一化加权合并。

5.5 知识更新

问题: 产品更新了(新成分、新功效),知识库不及时更新会导致回答过时。

应对: 飞书机器人命令 + 管理后台双通道更新。管理员在飞书群里发 updateKnowledgeGraphByName,BEE+ 就能触发增量更新。

六、总结与展望

6.1 我们做到了什么

一套完整的 AI 智能客服系统,覆盖:

  • 基于知识图谱的 RAG 问答
  • 混合检索(PGVector + BM25)
  • 多模型编排(GPT-4o / qwen-max / text-embedding-3)
  • 查询改写 + 意图识别 + 实体域识别
  • 健康报告 OCR + 分析 + 产品推荐
  • 多渠道接入(App / 企微 / 飞书)
  • SSE 流式响应 + 自研服务发现 + MQ 异步持久化

6.2 Agent 的下一步

参考行业趋势,我们的系统未来可以往这几个方向演进:

  1. 多 Agent 协作:不同 Agent 分工负责产品咨询、售后服务、订单查询,通过协调器统一调度
  2. 反思机制(Reflection):Agent 生成回答后自动检查质量,不合格就重新生成
  3. 长期记忆增强:利用用户历史偏好做个性化推荐,而不只是基于当前问题检索
  4. 工具扩展:接入更多外部工具(天气查询、物流追踪、订单系统),让 Agent 能完成更复杂的任务
  5. 微调优化:基于用户反馈数据微调开源模型,提升专业领域的回答质量

Agent 不是一蹴而就的。就像 LILIAN WENG 说的:Agent 的成败将是决定这一场 GPT 革命是否是新一代工业革命的关键。 我们已经在路上了。

参考资料:

  • Lilian Weng: LLM Powered Autonomous Agents
  • 吴恩达: Agent 四种设计模式(Reflection / Tool Use / Planning / Multiagent Collaboration)
  • XAgent 双循环机制、MetaGPT SOP 编码、MemGPT 记忆管理
  • 微信公众号:格林 | 神州问学《Agent如何帮助大模型"增强记忆"?》
  • 微信公众号:神州问学《AI Agent规划能力全面拆解》

Last updated: